快速入门Java堆分析

本文演示如何通过ATP的Java堆分析,寻找应用出现内存不足错误的原因。

1. 生成数据源并上传至ATP

假设我们观察到生产环境中的应用出现如下内存不足的报错:

java.lang.OutOfMemoryError: Java heap space
Exception in thread "Thread-3" Exception in thread "Thread-1" java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java heap space
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
Exception in thread "Thread-6" java.lang.OutOfMemoryError: Java heap space

这时我们可以生成应用的Heap dump文件,并将它上传到ATP,然后开始分析(具体操作参见开始使用ATP)。

2. 使用ATP堆分析

分析结果界面如下。通常我们会先查看【综合报表】查看堆大小、生成时间、JDK版本等信息,排除误操作,确认该文件和我们要分析的应用匹配。

image

然后进入【对象报表】界面,发现【class App @ 0x716500ed0】占据了堆中99.9%的内存,但是这是一个类,类本身不会占用很多内存,所以我们继续单击我引用谁,查看这个类引用的数据:

image

此时我们可以看到,实际上是App这个类有一个ConcurrentHashMap静态字段,这个容器持有3.76GB内存。

image

展开ConcurrenthashMap的节点,它的key是Integer类型,val是App$Holder类型,右侧显示App$Holder这个对象有两个字段:data、processed。

image

接着单击class App对象,从右侧可以知道它有一个静态字段queue。

image

3. 结论

根据以上收集到的信息,我们可以部分还原出问题的Java代码,大概如下:

class App {
    static class Holder {
        public boolean processed;
        byte[] data = new byte[1024 * 1024 * 50];
    }
    // 3.76GB
    static ConcurrentHashMap<Integer, Holder> queue = new ConcurrentHashMap<>();
}

即queue这个容器持有大量内存,结合具体Java源码,到这里我们基本上就能排查出问题了。